linux进程间通信之System V 信号量(semaphore)用法详解 |
您所在的位置:网站首页 › 信号量S>0 › linux进程间通信之System V 信号量(semaphore)用法详解 |
信号量是一种不同进程或不同线程间的同步方法,有System V信号量和Posix信号量。本文介绍System V 信号量,其在内核中维护,可用于进程间或线程间的同步,本文只介绍进程间同步。 信号量一般有两种,二值信号量(binary semaphore)和计数信号量(counting semaphore)。二值信号量: 顾名思义,其值只有两种0或1,相当于互斥量,当值为1时资源可用;而当值为0时,资源被锁住,进程阻塞无法继续执行。计数信号量: 其值是在0到某个限制值之间的信号量。 System V信号量是指的计数信号量集(set of counting semaphores),是一个或多个信号量的集合,其中每个都是计数信号量。(注:System V 信号量是计数信号量集,Posix 信号量是单个计数信号量。) System V 信号量函数头文件及相关函数原型:#include int semget(key_t key, int nsems, int oflag);功能:创建一个信号量集或访问一个已经存在的信号量集返回值:成功返回非负的标识符,出错返回-1参数:key是信号量的键值,多个进程可以通过这个键值访问同一个信号量;nsems参数指定信号量集合中的信号量数,一般设为1,如果不创建新的信号量集,只是访问一个已经存在的集合,可以把该参数设为0,一旦创建完一个信号量集,就不能改变其中的信号量数;oflag同open()权限位,IPC_CREAT标示创建新的信号量,如果或上IPC_EXCL,若信号量已存在则出错,如果没有或上IPC_EXCL,若信号量存在也不会出错。 int semctl(int semid, int semnum, int cmd, ... /*union semun arg */);功能: 信号量控制操作。返回值:若成功,根据cmd不同返回不同的值,IPC_STAT,IPC_SETVAL,IPC_RMID返回0,IPC_GETVAL返回信号量当前值;出错返回-1.参数:semid标示操作的信号量集;semnum标示该信号量集内的某个成员(0,1等,直到nsems-1),semnum值仅仅用于GETVAL,SETVAL,GETNCNT,GETZCNT,GETPID,通常取值0,也就是第一个信号量;cmd:指定对单个信号量的各种操作,IPC_STAT,IPC_GETVAL,IPC_SETVAL,IPC_RMID;arg: 可选参数,取决了第三个参数cmd。 int semop(int semid, struct sembuf *opstr, size_t nops);功能:操作信号量,P,V 操作返回值:成功返回信号量标识符,出错返回-1参数:semid:信号量集标识符;nops是opstr数组中元素数目,通常取值为1;opstr指向一个结构数组struct sembuf{short sem_num;short sem_op;short sem_flg;} 一般编程步骤:1. 创建信号量或获得在系统中已存在的信号量 1). 调用semget(). 2). 不同进程使用同一个信号量键值来获得同个信号量2. 初始化信号量 1).使用semctl()函数的SETVAL操作 2).当使用二维信号量时,通常将信号量初始化为13.进行信号量PV操作 1). 调用semop()函数 2). 实现进程之间的同步和互斥4.如果不需要该信号量,从系统中删除 1).使用semctl()函数的IPC_RMID操作 代码举例,父子进程间的同步sem_test.c #include #include #include #include #include #include #include #define USE_SYSTEMV_SEM 1 #define DELAY_TIME 2 union semun { int val; struct semid_ds *buf; unsigned short *array; }; // 将信号量sem_id设置为init_value int init_sem(int sem_id,int init_value) { union semun sem_union; sem_union.val=init_value; if (semctl(sem_id,0,SETVAL,sem_union)==-1) { perror("Sem init"); exit(1); } return 0; } // 删除sem_id信号量 int del_sem(int sem_id) { union semun sem_union; if (semctl(sem_id,0,IPC_RMID,sem_union)==-1) { perror("Sem delete"); exit(1); } return 0; } // 对sem_id执行p操作 int sem_p(int sem_id) { struct sembuf sem_buf; sem_buf.sem_num=0;//信号量编号 sem_buf.sem_op=-1;//P操作 sem_buf.sem_flg=SEM_UNDO;//系统退出前未释放信号量,系统自动释放 if (semop(sem_id,&sem_buf,1)==-1) { perror("Sem P operation"); exit(1); } return 0; } // 对sem_id执行V操作 int sem_v(int sem_id) { struct sembuf sem_buf; sem_buf.sem_num=0; sem_buf.sem_op=1;//V操作 sem_buf.sem_flg=SEM_UNDO; if (semop(sem_id,&sem_buf,1)==-1) { perror("Sem V operation"); exit(1); } return 0; } int main() { pid_t pid; #if USE_SYSTEMV_SEM int sem_id; key_t sem_key; sem_key=ftok(".",'A'); printf("sem_key=%x\n",sem_key); //以0666且create mode创建一个信号量,返回给sem_id sem_id=semget(sem_key,1,0666|IPC_CREAT); printf("sem_id=%x\n",sem_id); //将sem_id设为1 init_sem(sem_id,1); #endif if ((pid=fork()) |
今日新闻 |
推荐新闻 |
CopyRight 2018-2019 办公设备维修网 版权所有 豫ICP备15022753号-3 |